/*
 * This file is part of the Boring Engine's Kirby Game.
 *
 * Copyright (c) 2011 by pf5234 <pf5234@users.sourceforge.net>.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

package kirby;

import com.googlecode.boringengine.Animator;
import com.googlecode.boringengine.DefaultFont;
import com.googlecode.boringengine.GameEngine;
import com.googlecode.boringengine.Font;
import com.googlecode.boringengine.GameLoader;
import com.googlecode.boringengine.GameSettings;
import com.googlecode.boringengine.Input;
import com.googlecode.boringengine.Log;
import com.googlecode.boringengine.PauseMenu;
import com.googlecode.boringengine.Render;
import com.googlecode.boringengine.SoundSystem;
import com.googlecode.boringengine.Util;
import com.googlecode.boringengine.lua.LuaFunction;
import com.googlecode.boringengine.lua.LuaInterpreter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Iterator;
import kirby.misc.Door;

public class Game implements GameEngine {

    private Font font;
    private Kirby kirby;
    private Level level;
    private ArrayList<GameObject> objects;
    private ArrayList<Item> items;
    private ArrayList<Projectile> projectiles;
    private boolean isPaused, takeScreenshot;
    private static int music;
    private double tempo = 1;
    private String newLevel;

    public void init(GameLoader loader) {
        Resources.init(loader);
        PauseMenu.add("Inventory", new Animator("resources/gfx/enemies/waddledee", loader),
                new OpenInv(), true);
        objects = new ArrayList<GameObject>();
        items = new ArrayList<Item>();
        projectiles = new ArrayList<Projectile>();
        SoundSystem.openMusic("resources/music/KirbysAdventure.nsf");
        font = DefaultFont.getDefaultFont();
        newLevel = "testlevel"; changeLevel();
        SoundSystem.play();
        Door.setGame(this);
    }

    public void update() {
        if (newLevel != null) changeLevel();
        if (Input.isPressed(KeyEvent.VK_A, 20)) {
            isPaused = !isPaused;
        }
        if (Input.isPressed(KeyEvent.VK_TAB, 20)) {
            takeScreenshot = true;
        }
        if (Input.isPressed(KeyEvent.VK_Q, 20)) {
            if (music - 1 == 0) music = 58;
            else music -= 1;
            SoundSystem.changeTrack(music);
        } else if (Input.isPressed(KeyEvent.VK_W, 20)) {
            if (music + 1 == 59) music = 1;
            else music += 1;
            SoundSystem.changeTrack(music);
        }
        if (Input.isPressed(KeyEvent.VK_E, 15)) {
            tempo -= .05;
            if (tempo < 0) tempo = 0;
            SoundSystem.setSpeed(tempo);
        } else if (Input.isPressed(KeyEvent.VK_R, 15)) {
            tempo += .05;
            if (tempo > 5) tempo = 5;
            SoundSystem.setSpeed(tempo);
        }
        HUD.setDebugString(String.format("Music #%d, Tempo %.0f%%", music, tempo*100));
        if (!isPaused) {
            ParticleSystem.update();
            kirby.update();
            for (Projectile projectile : projectiles)
                projectile.update();
            for (GameObject o : objects)
                o.update();
            CollisionDetection.checkCollide(objects, kirby, projectiles);
            synchronized (objects) {
                int addenemys = 0;
                Iterator<GameObject> i = objects.iterator();
                while (i.hasNext()) {
                    GameObject o = i.next();
                    if (o instanceof Item && ((Item)o).isAnItem()) {
                        i.remove();
                        items.add((Item) o);
                        Inventory.add((Item) o);
                    }
                    if (o instanceof Enemy && ((Enemy)o).isDead()) {
                        i.remove();
                        addenemys++;
                    }
                }
                for (int j = 0; j < addenemys; j++)
                    objects.add(new TestEnemy());
            }
        }
        Camera.update();
        SoundSystem.update();
    }

    public void draw() {
        if (newLevel != null) return;
        if (takeScreenshot) {
            takeScreenshot = false;
            Render.takeScreenshot(GameSettings.configDir + "screen" +
                    Util.getDateTime() + ".png");
        }
        Render.clearScreen();
        Camera.beginDraw();
        level.drawBackground();
        ParticleSystem.draw();
        synchronized (objects) {
            for (GameObject o : objects)
                o.draw();
        }
        kirby.draw();
        for (Projectile projectile : projectiles)
            projectile.draw();
        level.drawForeground();
        Camera.endDraw();
        HUD.draw();
    }

    public void quit() {}
    
    @LuaFunction
    public void changeLevel(String levelName) {
        newLevel = levelName;
    }
    private void changeLevel() {
        try {
            Level l = new Level(newLevel);
            level = l;
        } catch (Exception e) {
            Log.warn("Exception on loading %s: %s", newLevel, e);
            newLevel = null;
            return;
        }
        objects.clear();
        items.clear();
        LuaInterpreter.addObject(new Camera(), "camera");
        LuaInterpreter.addObject(this, "game");
        CollisionDetection.setSolidMap(level.getSolidMap());
        music = level.getMusic();//(int)(Math.random()*58)+1;
        SoundSystem.changeTrack(music);
        kirby = new Kirby(level.getSpawnX(), level.getSpawnY());
        HUD.setLevelName(level.getName());
        projectiles.clear();
        kirby.setProjectiles(projectiles);
        LuaInterpreter.addObject(kirby, "kirby");
        HUD.init(kirby, font);
        Enemy e = new TestEnemy();
        objects.add(e);
        objects.addAll(level.getObjects());
        Item i = new TestItem();
        items.add(i); Inventory.add(i);
        GameObject.setLevel(level);
        Camera.setLevel(level);
        Camera.follow(kirby);
        newLevel = null;
        try {Thread.sleep(10000);} catch (InterruptedException ex) {}
    }

    private class OpenInv implements Runnable {

        public void run() {
            Util.addMenu(Inventory.getMenu());
        }

    }
}
